package com.origin.src.datasource.sharding;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.driver.api.ShardingSphereDataSourceFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

//@Component
@Slf4j
public class ShardingDataSource {

    @Bean("dataSource")
    public DataSource getDataSource() throws SQLException {
        ShardingConfig config = initConfig();
        Properties props = new Properties();
//        props.setProperty("sql-show", Boolean.TRUE.toString());

        return ShardingSphereDataSourceFactory.createDataSource(
                createDataSourceMap(config),
                List.of(
                        ShardingConfigTool.getRuleConfig(config)
                        , ShardingConfigTool.getEncryptRuleConfiguration()
                ),
                props);
    }

    public static ShardingConfig initConfig() {
        ShardingConfig config = new ShardingConfig();
        config.setDbNamePrefix("app_");
        config.setLogicTable("t_user");
        config.setDbMax(1);
        config.setTbMax(3);
        config.setDbShardColumn("user_id");
        config.setTbShardColumn("user_id");
        config.setPrimaryKeyColumn("user_id");
        config.setKeyGeneratorName("SNOWFLAKE");
        config.setDbShardingAlgorithmName("BASE64_CRC32_MOD");
        config.setTbShardingAlgorithmName("CRC32_MOD");
        config.setAuditStrategy("DML_SHARDING_CONDITIONS");
        return config;
    }


    public static Map<String, DataSource> createDataSourceMap(ShardingConfig config) {
        Map<String, DataSource> map = new HashMap<>();
        for (int i = 0; i <= config.getDbMax(); i++) {
            String dbName = config.getDbNamePrefix() + i;
            map.put(dbName, createDataSource(dbName));

        }
        return map;
    }


    public static DataSource createDataSource(String dbName) {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setJdbcUrl("jdbc:mysql://localhost:3306/" + dbName + "?serverTimezone=GMT%2B8&autoReconnect=true&failOverReadOnly=false&autoReconnect=true&autoReconnectForPools=true");
        hikariConfig.setUsername("root");
        hikariConfig.setPassword("root");
        hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
        hikariConfig.setMaximumPoolSize(8);
        hikariConfig.setMinimumIdle(0);
        hikariConfig.setPoolName(dbName);
        return new HikariDataSource(hikariConfig);

    }

    public static void initTable(String dbPrefix, int dbMax, int tableMax) {

        try {
            for (int i = 0; i <= dbMax; i++) {
                String dbName = dbPrefix + i;
                DataSource dataSource = createDataSource(dbName);
                Connection connection = dataSource.getConnection();
                Statement statement = connection.createStatement();

                for (int t = 0; t <= tableMax; t++) {
                    statement.execute("DROP TABLE IF EXISTS `t_user_" + t + "`");
                    statement.execute("CREATE TABLE `t_user_" + t + "` (\n" +
                            "  `user_id` bigint NOT NULL,\n" +
                            "  `user_name` varchar(255) DEFAULT NULL,\n" +
                            "  `user_phone` varchar(255) DEFAULT NULL,\n" +
                            "  `user_email` varchar(255) DEFAULT NULL,\n" +
                            "  `login_password` varchar(255) DEFAULT NULL,\n" +
                            "  `login_pwd` varchar(255) DEFAULT NULL,\n" +
                            "  PRIMARY KEY (`user_id`)\n" +
                            ")");

                    statement.execute("DROP TABLE IF EXISTS `t_order_" + t + "`");
                    statement.execute("CREATE TABLE `t_order_" + t + "` (\n" +
                            "  `order_id` bigint NOT NULL,\n" +
                            "  `user_id` bigint NOT NULL,\n" +
                            "  `order_name` varchar(255) DEFAULT NULL,\n" +
                            "  `pay_amount` NUMERIC(15,2) DEFAULT NULL,\n" +
                            "  `user_address` varchar(255) DEFAULT NULL,\n" +
                            "  PRIMARY KEY (`order_id`)\n" +
                            ")");
                }
            }
        } catch (Exception e) {
            log.error("db error", e);
        }
    }

    public static void main(String[] args) {
        ShardingConfig conf = ShardingDataSource.initConfig();
        initTable(conf.getDbNamePrefix(), conf.getDbMax(), conf.getTbMax());
    }

}
